package com.example.tool;

import com.alibaba.fastjson2.JSONObject;
import com.example.tool.ck.ClickhouseConfig;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXCheckBox;
import com.jfoenix.controls.JFXComboBox;
import com.jfoenix.controls.JFXDatePicker;
import io.datafx.controller.ViewController;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.chart.*;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.util.Pair;
import lombok.Data;
import lombok.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@ViewController(value = "/fxml/clickhouse_store.fxml", title = "ck")
public class CkStoreController {

    @FXML
    private HBox storeBox;

    @FXML
    private JFXButton refreshBtn;


    @FXML
    private JFXComboBox<String> datasourceCombo;

    @FXML
    private JFXComboBox<Label> staticMode;

    @FXML
    private JFXComboBox<Label> staticType;

    private static final Function<LocalDate, Date> localDateDateFunction = localDate -> {
        String value = localDate.toString();
        try {
            return new SimpleDateFormat("yyyy-MM-dd").parse(value);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    };
    private static final Function<Pair<Date, LocalTime>, Date> localTimeFunction = pair -> {
        Date date = pair.getKey();
        String time = pair.getValue().toString();
        String timeStr = new SimpleDateFormat("yyyy-MM-dd").format(date) + " " + time;
        try {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(timeStr);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    };
    private static JdbcTemplate clickhouseTemplate;

    @Data
    static class StoreVo {
        private String database;
        private String table;

        private Double rowNum;

        private Double unCompressGb;

        private Double compressGb;
    }

    // 自定义的时间轴标签格式化器
    //@PostConstruct
    public void initialize() throws ParseException {
        clickhouseTemplate = new ClickhouseConfig().clickhouseTemplate();

        String sql = "select database,count(distinct table) from system.parts group by database";

        List<JSONObject> data = clickhouseTemplate.query(sql, (rs, rowNum) -> {
            JSONObject object = new JSONObject();
            String database = rs.getString(1);
            int tableNum = rs.getInt(2);
            object.put("database", database);
            object.put("tableNum", tableNum);
            return object;
        });

        Consumer<Pair<List<JSONObject>, JFXComboBox<String>>> initComboBoxFun = tuple3 -> {
            JFXComboBox<String> comboBox = tuple3.getValue();
            ObservableList<String> children = comboBox.getItems();
            children.clear();
            children.add("--请选择--");
            List<JSONObject> sourceGroup = tuple3.getKey();
            for (JSONObject bucket : sourceGroup) {
                String source = bucket.getString("database");
                long docCount = bucket.getInteger("tableNum");
                children.add(source + "(" + docCount + ")");
            }
        };
        initComboBoxFun.accept(new Pair<>(data, datasourceCombo));
        datasourceCombo.setValue(datasourceCombo.getItems().get(0));
        staticMode.setValue(staticMode.getItems().get(0));
        staticType.setValue(staticType.getItems().get(0));

        refreshTable();

        refreshBtn.setOnAction(event -> refreshTable());

    }

    private void refreshTable() {
        storeBox.getChildren().removeIf(x -> true);
        final NumberAxis yAxis = new NumberAxis();//定义一个数字轴起名为y轴
        final CategoryAxis xAxis = new CategoryAxis();//定义一个分类轴起名为x轴
        final BarChart<Number, String> bc =
                new BarChart<>(yAxis, xAxis);//创建一个柱状图(条形图)

        Label staticModeLabel = staticMode.getValue();
        boolean isTableMode = staticModeLabel.getText().equals("表");

        Label staticTypeValue = staticType.getValue();
        boolean isRow = staticTypeValue.getText().equals("row");

        String database = datasourceCombo.getValue();

        String sql = "select database, table,length(groupUniqArray(name)), round(sum(rows) / 10000 / 10000, 2)  rowNum,\n" +
                "        round(sum(data_uncompressed_bytes) / 1024 / 1024/1024, 2)  unCompressGb,\n" +
                "       round(sum(data_compressed_bytes) / 1024 / 1024/1024, 2)  compressGb\n" +
                "from system.parts\n" +
                "group by database, table\n" +
                "order by sum(rows) asc";
        if (!isRow) {
            sql = sql.replace("order by sum(rows) asc", "order by sum(data_compressed_bytes) asc");
        }

        List<StoreVo> storeVoList = clickhouseTemplate.query(sql, (resultSet, i) -> {
            StoreVo object = new StoreVo();
            object.setDatabase(resultSet.getString("database"));
            object.setTable(resultSet.getString("table"));
            object.setRowNum(resultSet.getDouble("rowNum"));
            object.setUnCompressGb(resultSet.getDouble("unCompressGb"));
            object.setCompressGb(resultSet.getDouble("compressGb"));
            return object;
        });
        if (!isTableMode) {

            storeVoList = storeVoList.stream().collect(Collectors.groupingBy(StoreVo::getDatabase)).entrySet().stream().map(x -> {
                String databaseName = x.getKey();
                List<StoreVo> value = x.getValue();
                StoreVo storeVo = new StoreVo();
                storeVo.setDatabase(databaseName);
                storeVo.setTable(databaseName);
                storeVo.setRowNum(0d);
                storeVo.setCompressGb(0d);
                storeVo.setUnCompressGb(0d);
                for (StoreVo vo : value) {
                    storeVo.setRowNum(storeVo.rowNum + vo.getRowNum());
                    storeVo.setCompressGb(storeVo.getCompressGb() + vo.getCompressGb());
                    storeVo.setUnCompressGb(storeVo.getUnCompressGb() + vo.getUnCompressGb());
                }
                storeVo.setRowNum(Double.valueOf(storeVo.rowNum * 100).intValue() / 100d);
                storeVo.setCompressGb(Double.valueOf(storeVo.getCompressGb() * 100).intValue() / 100d);
                storeVo.setUnCompressGb(Double.valueOf(storeVo.getUnCompressGb() * 100).intValue() / 100d);
                return storeVo;
            }).collect(Collectors.toList());

        }
        if (!isRow && database.equals("--请选择--") && !isTableMode) {
            Double compressDb = storeVoList.stream().map(StoreVo::getCompressGb).reduce(Double::sum).orElse(0d);
            StoreVo storeVo = new StoreVo();
            storeVo.setDatabase("磁盘剩余");
            storeVo.setTable("磁盘剩余");
            storeVo.setRowNum(1d);
            storeVo.setCompressGb(Double.valueOf(197 - compressDb).intValue()+0d);
            storeVo.setUnCompressGb(0d);
            storeVoList.add(storeVo);

        }


        if(isRow){
            storeVoList = storeVoList.stream().filter(x->x.getRowNum()>=0.1d).collect(Collectors.toList());
        }else{
            storeVoList = storeVoList.stream().filter(x->x.getCompressGb()>=1).collect(Collectors.toList());
        }
        if (!database.equals("--请选择--")) {
            storeVoList = storeVoList.stream().filter(x -> database.contains(x.getDatabase())).collect(Collectors.toList());
        }


        if (!isTableMode) {
            xAxis.setLabel("数据库名称");//设置x轴标签
        } else {
            xAxis.setLabel("表名称");//设置x轴标签
        }
        if (isRow) {
            bc.setTitle("存储亿行数");//设置图的标题
            yAxis.setLabel("亿行数");//设置y轴标签
        } else {
            bc.setTitle("存储GB");//设置图的标题
            yAxis.setLabel("GB");//设置y轴标签
        }

        Map<String, String> viewMap = new HashMap<>();
        viewMap.put(".inner_id.dbc7ab36-3027-438d-8cb0-01944118ad17", "t_order_profit_info_view");
        viewMap.put(".inner_id.43eafcd9-a944-4497-8538-7df3703371aa", "t_local_food_profit_day_v2_view");

        if (isRow) {
            XYChart.Series<Number, String> series1 = new XYChart.Series<Number, String>();//创建数据序列1
            series1.setName("row");//序列标识
            for (StoreVo storeVo : storeVoList) {
                XYChart.Data<Number, String> d2 = null;
                if (viewMap.containsKey(storeVo.getTable())) {
                    d2 = new XYChart.Data<>(storeVo.getRowNum(), viewMap.get(storeVo.getTable()));
                } else {
                    d2 = new XYChart.Data<>(storeVo.getRowNum(), storeVo.getTable());
                }
                series1.getData().add(d2);
                Label label = new Label(storeVo.getRowNum() + "");
                label.setStyle("-fx-alignment: center;-fx-text-fill: blue");
                d2.setNode(label);
            }
            bc.getData().add(series1);
        } else {
            XYChart.Series<Number, String> series2 = new XYChart.Series<>();//创建数据序列1
            series2.setName("gb");//序列标识
            for (StoreVo storeVo : storeVoList) {
                XYChart.Data<Number, String> d2 = null;
                if (viewMap.containsKey(storeVo.getTable())) {
                    d2 = new XYChart.Data<>(storeVo.getCompressGb()*100, viewMap.get(storeVo.getTable()));
                } else {
                    d2 = new XYChart.Data<>(storeVo.getCompressGb()*100, storeVo.getTable());
                }
                series2.getData().add(d2);
                Label label = new Label(storeVo.getCompressGb() + "");
                label.setStyle("-fx-alignment: center;-fx-text-fill: #14306b");
                d2.setNode(label);
            }
            bc.getData().add(series2);
        }
        bc.setBarGap(5);
        bc.setCategoryGap(1);
        bc.setPrefHeight(1200);
        bc.setPrefWidth(2500);

        storeBox.getChildren().add(bc);
    }

    public String getBeforeDay(String date) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date taskDate = simpleDateFormat.parse(date);
        Date beforeDate = new Date(taskDate.getTime() - 24 * 3600L * 1000);
        return simpleDateFormat.format(beforeDate);
    }


    private List<String> getDates(Date begin, Date end) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String b = dateFormat.format(begin);
        String e = dateFormat.format(end);
        if (b.equals(e)) {
            return Collections.singletonList(b);
        }
        ArrayList<String> dates = new ArrayList<>();
        dates.add(b);
        while (!b.equals(e)) {
            b = dateFormat.format(new Date(dateFormat.parse(b).getTime() + 24 * 3600L * 1000));
            dates.add(b);
        }
        if (!dates.contains(e)) {
            dates.add(e);
        }
        return dates;
    }

    private void addSeries(LineChart<String, Number> barChart, List<JSONObject> data, String maxQps, Label label) {
        XYChart.Series<String, Number> qpsSeries = new XYChart.Series<>();
        qpsSeries.setName(maxQps);
        for (JSONObject bucket : data) {
            int qps = bucket.getInteger(maxQps);
            long time = bucket.getLong("time");
            JSONObject extra = new JSONObject();
            extra.put("x", new SimpleDateFormat("HH:mm").format(new Date(time)));
            extra.put("y", qps);
            qpsSeries.getData().add(new XYChart.Data<>(new SimpleDateFormat("HH:mm").format(new Date(time)), qps,
                    extra));
        }
        barChart.getData().add(qpsSeries);
        for (XYChart.Data<String, Number> datum : qpsSeries.getData()) {
            JSONObject extraValue = (JSONObject) datum.getExtraValue();
            datum.getNode().setOnMousePressed(event -> {
                label.setTranslateX(event.getSceneX() - barChart.getWidth());
                label.setTranslateY(event.getSceneY());

                label.setText("x:" + extraValue.get("x") + "\n" + maxQps + ":" + extraValue.get("y"));
            });

        }
    }
}
